/*
 * Copyright (C) 2014 Alpha, Inc.
 * This is NOT a freeware, use is subject to license terms.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gehua.octopus.rpc.starter;

import cc.gehua.octopus.rpc.common.classloader.Context;
import cc.gehua.octopus.rpc.common.classloader.OctopusClassLoader;
import cc.gehua.octopus.rpc.common.resource.Resource;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.util.Map;
import java.util.StringTokenizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author guna
 */
public class StartProcess implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(StartProcess.class);
    //private final String[] args;
    private Method methodStop;
    private final Context context;

    public StartProcess(Context context) {
        this.context = context;
    }

    @Override
    public void run() {
        OctopusClassLoader cl;
        try {
            cl = new OctopusClassLoader(context);
        } catch (IOException e) {
            LOGGER.error("Init classloader error.", e);
            return;
        }
        
        
        //cl.setParentLoaderPriority(false);
        Resource res;
        try {

            res = Resource.newResource(configureAPPBase);
            Resource addPath = res.addPath("lib");
            cl.addJars(addPath);
            LOGGER.info("Lib path:{}", addPath);
            cl.addClassPath(res.addPath("conf"));
        } catch (IOException e) {
            LOGGER.error("Set ClassPath error.", e);
            return;
        }
        configClassLoader(configureAPPBase,processArgs, cl);
        Thread.currentThread().setContextClassLoader(cl);
        try {
            Class<?> loadClass = cl.loadClass("com.acfun.octopus.server.app.SpringApp");
            Method setapp = loadClass.getMethod("setAPP_BASE", String.class);
            setapp.invoke(null, configureAPPBase);
            Method method = loadClass.getMethod("main", String[].class);
            method.invoke(null, (Object) args);
            methodStop = loadClass.getMethod("stop");
        } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            LOGGER.error("Init Server Error", e);
        }

    }

    private void configClassLoader(String baseRoute,Map<String, String> map, OctopusClassLoader classLoader) {
        //Has args plugin.lib?
        if (map.containsKey("plugin.jar.lib")) {
            splitStringToJarPath(baseRoute,map.get("plugin.jar.lib"),";",classLoader);
        }
        String property = System.getProperty("rpc-server.plugin.jar.lib");
        if (property != null && property.isEmpty()) {
            splitStringToJarPath(baseRoute,map.get("plugin.jar.lib"),";",classLoader);
        }
    }
    
    private void splitStringToJarPath(String baseRoute,String orign,String split,OctopusClassLoader classLoader){
        if(orign == null || orign.isEmpty() || split == null || split.isEmpty()){
            return;
        }
        StringTokenizer tokenizer = new StringTokenizer(orign, split);
            while (tokenizer.hasMoreTokens()) {
                String nextToken = tokenizer.nextToken();
                //fix it
                if(nextToken.isEmpty()){
                    continue;
                }
                if(nextToken.startsWith("./")){
                    nextToken = baseRoute + "/" + nextToken.substring(2);
                }
                LOGGER.info("Add plugin lib path : {}", nextToken);
                if (nextToken != null && !nextToken.isEmpty()) {
                    addJarPathToClassLoader(nextToken, classLoader);
                }
            }
    }

    private void addJarPathToClassLoader(String path, OctopusClassLoader classLoader) {
        try {
            Resource newResource = Resource.newResource(path);
            classLoader.addJars(newResource);
        } catch (MalformedURLException ex) {
            LOGGER.error("Add to class path error.", ex);
        }
    }

    public synchronized void destory() {
        if (methodStop == null) {
            return;
        }
        try {
            methodStop.invoke(null, new Object[]{});
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            LOGGER.error("Stop Server error", e);
        }

        LOGGER.info("Shutdown.");
    }

}
